<template>
  <view>
    <view class="wrap">
      <view class="title">
        <view>{{ userName }}</view>
      </view>
      <view class="content_box" id="box" ref="scrollBox">
        <view class="timer">{{ chatTime }}</view>
        <view :class="item.position == 'left' ? 'userbox2' : 'userbox'" v-for="(item, index) in chatList"
              :key="index" :id='"item"+index'>
          <view :class="item.position == 'left' ? 'nameInfo2' : 'nameInfo'">
            <view style="font-size: 14px">{{ item.position == 'left' ? item.uname : item.to_name }}</view>
            <view :class="item.position == 'left' ? 'contentText2' : 'contentText'">
              {{ item.msn }}
            </view>
          </view>
          <view>
            <image class="touxiang" :src="item.position == 'left' ?item.uavatar:item.to_avatar"/>
          </view>
        </view>
      </view>
      <view class="bottom">
        <textarea name="输入框" id="1" cols="20" rows="5" class="areaBox" v-model="inputValue"></textarea>
        <button :disabled="!inputValue" style="height: 30px;color: #58df4d;font-size: 14px;line-height: 30px;"
                @click="sendOut">发送</button>
      </view>
    </view>
  </view>
</template>

<script>
import {getConsultationList} from "@/api/drug/drugs"

let userAvatar = 'https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F0228%2F73326a0bj00s9jq7q003fd200sg00sgg005g005g.jpg&thumbnail=660x2147483647&quality=80&type=jpg';
let kf_avatar = 'https://bpic.588ku.com/element_origin_min_pic/19/03/07/4b84bb9a63ce351df3aca480eab68893.jpg';
export default {
  data() {
    return {
      chatTime: (() => {
        function padTo2Digits(num) {
          return num.toString().padStart(2, '0');
        }

        let date = new Date();
        return (
            [
              date.getFullYear(),
              padTo2Digits(date.getMonth() + 1),
              padTo2Digits(date.getDate()),
            ].join('-') +
            ' ' +
            [
              padTo2Digits(date.getHours()),
              padTo2Digits(date.getMinutes()),
              padTo2Digits(date.getSeconds()),
            ].join(':')
        );
      })(),
      page: 1,//聊天历史记录分页
      chatList: [],//聊天信息
      userName: this.$store.state.user.name,//用户名
      inputValue: "",//输入内容
      scrollTop: 0,//滚动条距离顶部距离
      infoList: null,//用户信息

      path: "ws://127.0.0.1:8080/websocket/message", //websocket链接地址
      ws: null, //建立的连接
      lockReconnect: false, //是否真正建立连接
      timeout: 10 * 1000, //30秒一次心跳
      timeoutObj: null, //心跳心跳倒计时
      serverTimeoutObj: null, //心跳倒计时
      timeoutnum: null, //断开 重连倒计时
      closeType: 1,//断开判断：0代表不重连，1代表重连
    }
  },
  onShow() {
    this.initWebpack();//初始化
    this.closeType = 1//进入改为1，代表如果断开链接自动重连
    this.getlishiList()//历史记录
    this.userName = this.userName//拿到缓存中的用户信息
  },
  onLoad(options) {
    // 选中得 药品id
    let selectedDrugId = options.selectedDrugId;
    // 选中的 药师
    let selectedPharmacistId = options.selectedPharmacistId;
    let selectedPharmacistName = options.selectedPharmacistName;
    // 问药人用户名
    let askUserName = options.askUserName;
    let askUserId = options.askUserId;
    //拿到上一个页面传过来的参数，内容是选中客服信息
    this.infoList = {
      selectedDrugId
      , selectedPharmacistId
      , askUserName
      , askUserId
      , kf_id: selectedPharmacistId
      , kfname: selectedPharmacistName
      , kf_avatar: kf_avatar
    }
    console.log('选中客服信息', options);
    // 修改标题
    wx.setNavigationBarTitle({
      title: '与药师['+this.infoList.kfname+']的会话'
    })

  },
  onPageScroll(e) {
    //监听滚动事件，如果滚动条等于0，代表滚动到最顶部，把分页加一，然后历史记录拉第二页数据，以此类推
    if (e.scrollTop == 0) {
      this.page++
      this.getlishiList(1)
      console.log('到顶部了')
    }
  },
  beforeDestroy() {
    this.closeType = 0 //离开页面前改为0，代表离开后断开链接不再重连
    this.ws.send({
      data: JSON.stringify({
        type: "online",
        data: {
          online: 0,
          user_type: 'user',
          is_tourist: this.$store.state.user.name ? 0 : 1
        }
      })
    })
    // 离开页面后关闭连接
    this.ws.close();
    // 清除时间
    clearTimeout(this.timeoutObj);
    clearTimeout(this.serverTimeoutObj);
  },
  methods: {
    //获取历史记录
    async getlishiList(type) {
      let response = await getConsultationList({
        pageNum: this.page,
        pageSize: 10,
        userId: null,// 由后台设值
        // 药师id
        pharmacistId: this.infoList.selectedPharmacistId,
        // 药品id
        drugId: this.infoList.selectedDrugId,
        // 排序
        orderByColumn:'consultationTime',
        isAsc:'asc'
      })

      /*
      // 后台格式
      [
        {
            "createBy": "",
            "createTime": null,
            "updateBy": "",
            "updateTime": null,
            "remark": null,
            "consultationId": 1,
            "userId": 102,
            "pharmacistId": 106,
            "drugId": 6,
            "question": "问1",
            "answer": "回复1",
            "consultationTime": null
        }
    ]
    // chatList数据格式
    [
      {
      position:'left/right',
      uname:'为回复时客服的名字'
      to_name:'为提问时用户的名字'
      msn:'消息内容'
      }
    ]
       */
      console.log('历史记录:', response.rows);
      let a = response.rows.map(history => ({
            //类型0_question;1_answer
            position: history.type === '1' ? 'left' : 'right',
            uname: history.type === '1' ? this.infoList.kfname : this.userName,
            uavatar: kf_avatar,
            to_avatar: userAvatar,
            msn: history.content
          })
      );
      this.chatList = a.concat(this.chatList)//用拿到的数据合并现有的数据，这样当加载第二页历史记录时，顺序不会乱
      if (type === 1) {//滚动到顶部触发方法会传入1，此时不需要调用滚动到最底部的方法
        return
      }
      this.setPageScrollTo()//滚动到最底部
    },
    //滚动条默认滚动到最底部
    setPageScrollTo(s, c) {
      let that = this
      this.$nextTick(() => {
        const query = uni.createSelectorQuery().in(this);
        query
            .select("#box")
            .boundingClientRect((rect) => {
              let height = rect.height;//拿到聊天框的高度
              console.log("聊天信息框高度: ", height);
              wx.pageScrollTo({
                scrollTop: height,//把距离顶部距离设置成聊天框高度，以此把滚动条顶到最底部
                duration: 100 // 滑动速度
              })
            })
            .exec();
      });
    },

    //发送消息
    sendOut() {
      this.chatList.push({
        msn: this.inputValue,
        position: "right",
        to_avatar: userAvatar,
        to_name: this.userName
      })
      let parms = {
        content: this.inputValue,
        uid: null,
        uname: this.userName,
        uavatar: userAvatar,
        to_uid: this.infoList.kf_id,
        to_name: this.infoList.kfname,
        to_avatar: this.infoList.kf_avatar,
        type: 'text',
        channel_type: 'wechat',
        // 新增传参
        from:'app',
        askUserName: this.infoList.askUserName,
        userId:this.infoList.askUserId,
        drugId:this.infoList.selectedDrugId,
        pharmacistId:this.infoList.selectedPharmacistId,
      }
      //通过websocket发送信息到后台
      this.ws.send({
        data: JSON.stringify({
          type: "chat",
          data: parms,
          // 新增传参
          msgType:'0',//类型0_question;1_answer
        })
      })
      this.inputValue = ''//点击发送后清空输入框
      this.setPageScrollTo()//滚动到最底部
      console.log('发送成功', this.inputValue);
    },

    // 初始化websocket链接
    initWebpack() {
      //实例
      this.ws = wx.connectSocket({
        url: this.path + "?from=app&userId=" + this.infoList.askUserId + "&drugId=" + this.infoList.selectedDrugId + "&pharmacistId=" + this.infoList.selectedPharmacistId,
      })
      //链接成功
      this.ws.onOpen((res) => {
        let that = this
        console.log("连接成功", that.ws.readyState);
        if (that.ws.readyState == 1) {
          // wx.sendSocketMessage({ //发送消息到后台，和send一样，这是微信的写法
          //   data: JSON.stringify({
          //     type: "login",
          //     data: {
          //       id: uni.getStorageSync("userinfo").wechatUsers.id,
          //       channel_type: 'wechat',
          //       uid: uni.getStorageSync("userinfo").id,
          //       openid: 'ojV4k6tnkv4_F1dddc3VwLeJ_QLs'
          //     }
          //   })
          // })
          this.ws.send({
            data: JSON.stringify({
              type: "online",
              data: {
                online: 1,
                user_type: 'user',
                is_tourist: this.$store.state.user.name ? 0 : 1
              }
            })
          })
        }
        that.start(); //链接成功后开启心跳
      })
      //链接异常
      this.ws.onError((res) => {
        console.log("出现错误");
        this.reconnect(); //重连
      })
      //链接断开
      this.ws.onClose((res) => {
        console.log("连接关闭");
        //断开链接时判断
        if (this.closeType == 0) {
          return
        }
        this.reconnect(); //重连
      })
      //后台返回消息
      this.ws.onMessage((res) => {
        console.log(res,9999999999999999999999)
        if (!res || !res.data||res.data ==='连接成功') {
          return;
        }
        console.log(1111111111111, res)
        let type = {type:'chat',data:{}};
        type.data.position = 'left'
        type.data.uname = this.infoList.kfname
        type.data.uavatar = this.infoList.kf_avatar
        type.data.msn = res.data;
        //后台返回消息，通过type字段判断是不是别人发送给我的消息
        if (type.type === 'chat') {
          this.chatList.push(type.data)//把消息添加到信息列表渲染
          this.setPageScrollTo() //滚动到最底部
          //console.log("收到后台信息：", JSON.parse(res.data));
        }

        this.reset(); //收到服务器信息，心跳重置
      })

    },
    //重新连接
    reconnect() {
      var that = this;
      //防止重复链接
      if (that.lockReconnect) {
        return;
      }
      that.lockReconnect = true;
      //没连接上会一直重连，设置延迟避免请求过多
      that.timeoutnum && clearTimeout(that.timeoutnum);
      that.timeoutnum = setTimeout(function () {
        that.initWebpack(); //新连接
        that.lockReconnect = false;
      }, 5000);
    },
    //重置心跳
    reset() {
      var that = this;
      clearTimeout(that.timeoutObj); //清除心跳倒计时
      clearTimeout(that.serverTimeoutObj); //清除超时关闭倒计时
      that.start(); //重启心跳
    },
    //开启心跳
    start() {
      var self = this;
      self.timeoutObj && clearTimeout(self.timeoutObj); //心跳倒计时如果有值就清除掉，防止重复
      self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj); //超时关闭倒计时如果有值就清除掉，防止重复
      self.timeoutObj = setTimeout(function () {
        if (self.ws.readyState == 1) {
          wx.sendSocketMessage({
            data: JSON.stringify({
              type: "ping"
            })
          })
        } else {
          self.reconnect();//重连
        }

        //如果超时了就关闭连接
        self.serverTimeoutObj = setTimeout(function () {
          self.ws.close();
        }, self.timeout);
      }, self.timeout);
    },
    //连接成功
  }
}
</script>

<style scoped>
.wrap {
  height: 100%;
  width: 100%;
  position: relative;
}

.touxiang {
  width: 50px;
  height: 50px;
  border-radius: 50%;
}

.areaBox {
  height: 40px;
}

.title {
  height: 40px;
  width: 100%;
  background-color: #eaeaea;
  display: flex;
  justify-content: center;
  align-items: center;
}

.bottom {
  min-height: 50px;
  width: 100%;
  border-top: 1px solid #eaeaea;
  background-color: #F1F1F1;
  position: fixed;
  bottom: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 5px;
  border-radius: 10px;
}

.content_box {
  /*
中间栏计算高度，110是包含了上下固定的两个元素高度90
这里padding：10px造成的上下够加了10，把盒子撑大了，所以一共是20要减掉
然后不知道是边框还是组件的原因，导致多出了一些，这里再减去5px刚好。不然会出现滚动条到顶或者底部的时候再滚动的话就会报一个错，或者出现滚动条变长一下的bug
*/
  height: calc(100% - 115px);
  overflow: auto;
  padding: 10px 10px 50px 10px;
}

.timer {
  text-align: center;
  color: #c2c2c2;
}

/* 发送的信息样式 */
/*
右边消息思路解释：首先大盒子userbox内放两个盒子，一个放头像，一个放用户名和发送的内容，我们先用flex让他横向排列。
然后把写文字的大盒子设置flex：1。这个属性的意思就是让这个元素撑满父盒子剩余位置。然后我们再把文字盒子设置flex，并把他对齐方式设置为尾部对齐就完成了基本的结构，然后微调一下就可以了
*/
.userbox {
  width: 100%;
  display: flex;
  margin-bottom: 10px;
}

.nameInfo {
  /* 用flex：1把盒子撑开 */
  flex: 1;
  margin-right: 10px;
  /* 用align-items把元素靠右对齐 */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

.contentText {
  background-color: #9eea6a;
  /* 把内容部分改为行内块元素，因为盒子flex：1把盒子撑大了，所以用行内块元素让内容宽度不根据父盒子来 */
  display: inline-block;
  /* 这四句是圆角 */
  border-top-left-radius: 10px;
  border-top-right-radius: 0px;
  border-bottom-right-radius: 10px;
  border-bottom-left-radius: 10px;
  /* 最大宽度限定内容输入到百分61换行 */
  max-width: 61%;
  padding: 5px 10px;
  /* 忽略多余的空白，只保留一个空白 */
  white-space: normal;
  /* 换行显示全部字符 */
  word-break: break-all;
  margin-top: 3px;
  font-size: 14px;
}

/* 接收的信息样式 */
/*
左边消息思路解释：跟上面一样，就是换一下位置，首先通过把最外层大盒子的排列方式通过flex-direction: row-reverse;属性翻转，也就是头像和文字盒子换位置
然后删除掉尾部对齐方式，因为不写这个默认是左对齐的。我们写的左边就没必要再写了。
*/
.userbox2 {
  width: 100%;
  display: flex;
  flex-direction: row-reverse;
  margin-bottom: 10px;
}

.nameInfo2 {
  /* 用flex：1把盒子撑开 */
  flex: 1;
  margin-left: 10px;
}

.contentText2 {
  background-color: #9eea6a;
  /* 把内容部分改为行内块元素，因为盒子flex：1把盒子撑大了，所以用行内块元素让内容宽度不根据父盒子来 */
  display: inline-block;
  /* 这四句是圆角 */
  border-top-left-radius: 0px;
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
  border-bottom-left-radius: 10px;
  /* 最大宽度限定内容输入到百分61换行 */
  max-width: 61%;
  padding: 5px 10px;
  /* 忽略多余的空白，只保留一个空白 */
  white-space: normal;
  /* 换行显示全部字符 */
  word-break: break-all;
  margin-top: 3px;
  font-size: 14px;
}
</style>

